/*-------------------------------------------------------------------------
 *
 * hash_xlog.h
 *    header file for Postgres hash AM implementation
 *
 * Portions Copyright (c) 2021 Huawei Technologies Co.,Ltd.
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/access/hash_xlog.h
 *
 *-------------------------------------------------------------------------
 */

#ifndef HASH_XLOG_H
#define HASH_XLOG_H

#include "access/xlogreader.h"
#include "lib/stringinfo.h"
#include "storage/off.h"

/* Number of buffers required for XLOG_HASH_SQUEEZE_PAGE operation */
#define HASH_XLOG_FREE_OVFL_BUFS      6

/*
 * XLOG records for hash operations
 */
#define XLOG_HASH_INIT_META_PAGE      0x00    /* initialize the meta page */
#define XLOG_HASH_INIT_BITMAP_PAGE    0x10    /* initialize the bitmap page */
#define XLOG_HASH_INSERT              0x20    /* add index tuple without split */
#define XLOG_HASH_ADD_OVFL_PAGE       0x30    /* add overflow page */
#define XLOG_HASH_SPLIT_ALLOCATE_PAGE 0x40    /* allocate new page for split */
#define XLOG_HASH_SPLIT_PAGE          0x50    /* split page */
#define XLOG_HASH_SPLIT_COMPLETE      0x60    /* completion of split operation */
#define XLOG_HASH_MOVE_PAGE_CONTENTS  0x70    /* remove tuples from one page
                                               * and add to another page */
#define XLOG_HASH_SQUEEZE_PAGE        0x80    /* add tuples to one of the previous
                                               * pages in chain and free the ovfl
                                               * page */
#define XLOG_HASH_DELETE              0x90    /* delete index tuples from a page */
#define XLOG_HASH_SPLIT_CLEANUP       0xA0    /* clear split-cleanup flag in primary
                                               * bucket page after deleting tuples
                                               * that are moved due to split */
#define XLOG_HASH_UPDATE_META_PAGE    0xB0    /* update meta page after vacuum */
#define XLOG_HASH_VACUUM_ONE_PAGE     0xC0    /* remove dead tuples from index page */

typedef enum {
    XLOG_HASH_INIT_META_PAGE_NUM = 0,
}XLogHashInitMetaPageEnum;

typedef enum {
    XLOG_HASH_INIT_BITMAP_PAGE_BITMAP_NUM = 0,
    XLOG_HASH_INIT_BITMAP_PAGE_META_NUM,
}XLogHashInitBitmapPageEnum;

typedef enum {
    XLOG_HASH_INSERT_PAGE_NUM = 0,
    XLOG_HASH_INSERT_META_NUM,
}XLogHashInsertEnum;

typedef enum {
    XLOG_HASH_ADD_OVFL_PAGE_OVFL_NUM = 0,
    XLOG_HASH_ADD_OVFL_PAGE_LEFT_NUM,
    XLOG_HASH_ADD_OVFL_PAGE_MAP_NUM,
    XLOG_HASH_ADD_OVFL_PAGE_NEWMAP_NUM,
    XLOG_HASH_ADD_OVFL_PAGE_META_NUM,
}XLogHashAddOvflPageEnum;

typedef enum {
    XLOG_HASH_SPLIT_ALLOCATE_PAGE_OBUK_NUM = 0,
    XLOG_HASH_SPLIT_ALLOCATE_PAGE_NBUK_NUM,
    XLOG_HASH_SPLIT_ALLOCATE_PAGE_META_NUM,
}XLogHashSplitAllocatePageEnum;

typedef enum {
    XLOG_HASH_SPLIT_PAGE_NUM = 0,
}XLogHashSplitPageEnum;

typedef enum {
    XLOG_HASH_SPLIT_COMPLETE_OBUK_NUM = 0,
    XLOG_HASH_SPLIT_COMPLETE_NBUK_NUM,
}XLogHashSplitCompleteEnum;

typedef enum {
    HASH_MOVE_BUK_BLOCK_NUM = 0,
    HASH_MOVE_ADD_BLOCK_NUM,
    HASH_MOVE_DELETE_OVFL_BLOCK_NUM,
}XLogHashMovePageEnum;

typedef enum {
    HASH_SQUEEZE_BUK_BLOCK_NUM = 0,
    HASH_SQUEEZE_ADD_BLOCK_NUM,
    HASH_SQUEEZE_INIT_OVFLBUF_BLOCK_NUM,
    HASH_SQUEEZE_UPDATE_PREV_BLOCK_NUM,
    HASH_SQUEEZE_UPDATE_NEXT_BLOCK_NUM,
    HASH_SQUEEZE_UPDATE_BITMAP_BLOCK_NUM,
    HASH_SQUEEZE_UPDATE_META_BLOCK_NUM,
}XLogHashSqueezePageEnum;

typedef enum {
    HASH_DELETE_BUK_BLOCK_NUM = 0,
    HASH_DELETE_OVFL_BLOCK_NUM,
}XLogHashDeleteEnum;

typedef enum {
    HASH_SPLIT_CLEANUP_BLOCK_NUM,
}XLogHashSplitCleanupEnum;

typedef enum {
    HASH_UPDATE_META_BLOCK_NUM,
} XLogHashUpdateMateEnum;

typedef enum {
    HASH_VACUUM_PAGE_BLOCK_NUM = 0,
    HASH_VACUUM_META_BLOCK_NUM,
} XLogHashVacuumPageEnum;

/*
 * xl_hash_split_allocate_page flag values, 8 bits are available.
 */
#define XLH_SPLIT_META_UPDATE_MASKS        (1<<0)
#define XLH_SPLIT_META_UPDATE_SPLITPOINT   (1<<1)

/*
 * This is what we need to know about a HASH index create.
 *
 * Backup block 0: metapage
 */
typedef struct xl_hash_createidx
{
    double num_tuples;
    RegProcedure procid;
    uint16 ffactor;
} xl_hash_createidx;

#define SizeOfHashCreateIdx (offsetof(xl_hash_createidx, ffactor) + sizeof(uint16))

/*
 * This is what we need to know about simple (without split) insert.
 *
 * This data record is used for XLOG_HASH_INSERT
 *
 * Backup Blk 0: original page (data contains the inserted tuple)
 * Backup Blk 1: metapage (HashMetaPageData)
 */
typedef struct xl_hash_insert
{
    OffsetNumber offnum;
} xl_hash_insert;

#define SizeOfHashInsert (offsetof(xl_hash_insert, offnum) + sizeof(OffsetNumber))

/*
 * This is what we need to know about addition of overflow page.
 *
 * This data record is used for XLOG_HASH_ADD_OVFL_PAGE
 *
 * Backup Blk 0: newly allocated overflow page
 * Backup Blk 1: page before new overflow page in the bucket chain
 * Backup Blk 2: bitmap page
 * Backup Blk 3: new bitmap page
 * Backup Blk 4: metapage
 */
typedef struct xl_hash_add_ovfl_page
{
    uint16 bmsize;
    bool bmpage_found;
} xl_hash_add_ovfl_page;

#define SizeOfHashAddOvflPage    \
    (offsetof(xl_hash_add_ovfl_page, bmpage_found) + sizeof(bool))

/*
 * This is what we need to know about allocating a page for split.
 *
 * This data record is used for XLOG_HASH_SPLIT_ALLOCATE_PAGE
 *
 * Backup Blk 0: page for old bucket
 * Backup Blk 1: page for new bucket
 * Backup Blk 2: metapage
 */
typedef struct xl_hash_split_allocate_page
{
    uint32 new_bucket;
    uint16 old_bucket_flag;
    uint16 new_bucket_flag;
    uint8 flags;
} xl_hash_split_allocate_page;

#define SizeOfHashSplitAllocPage    \
    (offsetof(xl_hash_split_allocate_page, flags) + sizeof(uint8))

/*
 * This is what we need to know about completing the split operation.
 *
 * This data record is used for XLOG_HASH_SPLIT_COMPLETE
 *
 * Backup Blk 0: page for old bucket
 * Backup Blk 1: page for new bucket
 */
typedef struct xl_hash_split_complete
{
    uint16 old_bucket_flag;
    uint16 new_bucket_flag;
} xl_hash_split_complete;

#define SizeOfHashSplitComplete \
    (offsetof(xl_hash_split_complete, new_bucket_flag) + sizeof(uint16))

/*
 * This is what we need to know about move page contents required during
 * squeeze operation.
 *
 * This data record is used for XLOG_HASH_MOVE_PAGE_CONTENTS
 *
 * Backup Blk 0: bucket page
 * Backup Blk 1: page containing moved tuples
 * Backup Blk 2: page from which tuples will be removed
 */
typedef struct xl_hash_move_page_contents
{
    uint16 ntups;
    bool is_prim_bucket_same_wrt;    /* true if the page to which
                                      * tuples are moved is same as
                                      * primary bucket page */
} xl_hash_move_page_contents;

#define SizeOfHashMovePageContents    \
    (offsetof(xl_hash_move_page_contents, is_prim_bucket_same_wrt) + sizeof(bool))

/*
 * This is what we need to know about the squeeze page operation.
 *
 * This data record is used for XLOG_HASH_SQUEEZE_PAGE
 *
 * Backup Blk 0: page containing tuples moved from freed overflow page
 * Backup Blk 1: freed overflow page
 * Backup Blk 2: page previous to the freed overflow page
 * Backup Blk 3: page next to the freed overflow page
 * Backup Blk 4: bitmap page containing info of freed overflow page
 * Backup Blk 5: meta page
 */
typedef struct xl_hash_squeeze_page
{
    BlockNumber prevblkno;
    BlockNumber nextblkno;
    uint16 ntups;
    bool is_prim_bucket_same_wrt;    /* true if the page to which
                                      * tuples are moved is same as
                                      * primary bucket page */
    bool is_prev_bucket_same_wrt;    /* true if the page to which
                                      * tuples are moved is the page
                                      * previous to the freed overflow
                                      * page */
} xl_hash_squeeze_page;

#define SizeOfHashSqueezePage    \
    (offsetof(xl_hash_squeeze_page, is_prev_bucket_same_wrt) + sizeof(bool))

/*
 * This is what we need to know about the deletion of index tuples from a page.
 *
 * This data record is used for XLOG_HASH_DELETE
 *
 * Backup Blk 0: primary bucket page
 * Backup Blk 1: page from which tuples are deleted
 */
typedef struct xl_hash_delete
{
    bool clear_dead_marking;     /* true if this operation clears
                                  * LH_PAGE_HAS_DEAD_TUPLES flag */
    bool is_primary_bucket_page; /* true if the operation is for
                                  * primary bucket page */
} xl_hash_delete;

#define SizeOfHashDelete    \
    (offsetof(xl_hash_delete, is_primary_bucket_page) + sizeof(bool))

/*
 * This is what we need for metapage update operation.
 *
 * This data record is used for XLOG_HASH_UPDATE_META_PAGE
 *
 * Backup Blk 0: meta page
 */
typedef struct xl_hash_update_meta_page
{
    double ntuples;
} xl_hash_update_meta_page;

#define SizeOfHashUpdateMetaPage    \
    (offsetof(xl_hash_update_meta_page, ntuples) + sizeof(double))

/*
 * This is what we need to initialize metapage.
 *
 * This data record is used for XLOG_HASH_INIT_META_PAGE
 *
 * Backup Blk 0: meta page
 */
typedef struct xl_hash_init_meta_page
{
    double num_tuples;
    RegProcedure procid;
    uint16 ffactor;
} xl_hash_init_meta_page;

#define SizeOfHashInitMetaPage        \
    (offsetof(xl_hash_init_meta_page, ffactor) + sizeof(uint16))

/*
 * This is what we need to initialize bitmap page.
 *
 * This data record is used for XLOG_HASH_INIT_BITMAP_PAGE
 *
 * Backup Blk 0: bitmap page
 * Backup Blk 1: meta page
 */
typedef struct xl_hash_init_bitmap_page
{
    uint16 bmsize;
} xl_hash_init_bitmap_page;

#define SizeOfHashInitBitmapPage    \
    (offsetof(xl_hash_init_bitmap_page, bmsize) + sizeof(uint16))

/*
 * This is what we need for index tuple deletion and to
 * update the meta page.
 *
 * This data record is used for XLOG_HASH_VACUUM_ONE_PAGE
 *
 * Backup Blk 0: bucket page
 * Backup Blk 1: meta page
 */
typedef struct xl_hash_vacuum_one_page
{
    RelFileNode hnode;
    int ntuples;

    /* TARGET OFFSET NUMBERS FOLLOW AT THE END */
} xl_hash_vacuum_one_page;

#define SizeOfHashVacuumOnePage \
    (offsetof(xl_hash_vacuum_one_page, ntuples) + sizeof(int))

extern void hash_redo(XLogReaderState *record);
extern void hash_desc(StringInfo buf, XLogReaderState *record);
extern const char *hash_identify(uint8 info);
extern bool IsHashVacuumPages(XLogReaderState *record);

#endif                            /* HASH_XLOG_H */
